﻿using System;
using System.ServiceModel;
using ProLinq.Wcf.Behaviors;

namespace ProLinq.Wcf.Extensions
{
	public static class ChannelExtensions
	{
		/// <summary>
		/// Ensures factory has proper configuration
		/// </summary>
		/// <param name="factory"></param>
		internal static void ApplyQueryableBehavior(this ChannelFactory factory)
		{
			if (factory.Endpoint.Behaviors.Find<QueryableBehavior>() == null)
			{
				factory.Endpoint.Behaviors.Add(new QueryableBehavior());
			}
		}

		/// <summary>
		/// Wraps WCF channel in queryable proxy.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="channel"></param>
		/// <returns></returns>
		internal static T WrapChannel<T>(T channel)
		{
			return (T) new QueryableServiceProxy<T>(channel).GetTransparentProxy();
		}

		/// <summary>
		/// Creates WCF channel for IQueryable contracts.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="factory"></param>
		/// <returns></returns>
		public static T CreateQueryableChannel<T>(this ChannelFactory<T> factory)
		{
			if (factory is QueryableChannelFactory<T>)
			{
				return factory.CreateChannel();
			}

			ApplyQueryableBehavior(factory);
			return WrapChannel(factory.CreateChannel());
		}

		/// <summary>
		/// Creates WCF channel for IQueryable contracts.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="factory"></param>
		/// <param name="address"></param>
		/// <returns></returns>
		public static T CreateQueryableChannel<T>(this ChannelFactory<T> factory, EndpointAddress address)
		{
			if (factory is QueryableChannelFactory<T>)
			{
				return factory.CreateChannel(address);
			}

			ApplyQueryableBehavior(factory);
			return WrapChannel(factory.CreateChannel(address));
		}

		/// <summary>
		/// Creates WCF channel for IQueryable contracts.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="factory"></param>
		/// <param name="address"></param>
		/// <param name="via"></param>
		/// <returns></returns>
		public static T CreateQueryableChannel<T>(this ChannelFactory<T> factory, EndpointAddress address, Uri via)
		{
			if (factory is QueryableChannelFactory<T>)
			{
				return factory.CreateChannel(address, via);
			}

			ApplyQueryableBehavior(factory);
			return WrapChannel(factory.CreateChannel(address, via));
		}
	}
}